package com.cuz.daileetcode;

import javafx.util.Pair;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Day45 {

    /**
     * 给一个包含n个整数元素的集合a，一个包含m个整数元素的集合b。
     * 定义magic操作为，从一个集合中取出一个元素，放到另一个集合里，且操作过
     * 后每个集合的平均值都大大于于操作前。
     * 注意以下两点:
     * 1）不可以把一个集合的元素取空，这样就没有平均值了
     * 2）值为x的元素从集合b取出放入集合a，但集合a中已经有值为x的元素，则a的
     * 平均值不变（因为集合元素不会重复），b的平均值可能会改变（因为x被取出了)
     * 问最多可以进行多少次magic操作?
     */
    static class Magic {
        static int magicOperationNum(int[] a, int[] b) {
            if (isArrayEmpty(a) || isArrayEmpty(b)) {
                return 0;
            }
            //对 数组进行统计，并且将较小平均值的数组放在 Pair的key
            Pair<StaticHelp, StaticHelp> sumAvgPair = StaticHelp.lessAvgFirst(a, b);
            StaticHelp lessAvgObj = sumAvgPair.getKey();
            StaticHelp betterAvgObj = sumAvgPair.getValue();
            //较小平均值
            double lessAvg = lessAvgObj.avg;
            //较小平均值数组中
            double lessSum = lessAvgObj.sum;
            //较小平均值数组
            int[] lessAvgArray = lessAvgObj.arr;
            //较小平均值数组长度
            int lessLen = lessAvgArray.length;
            double betterAvg = betterAvgObj.avg;
            double betterSum = betterAvgObj.sum;
            int[] betterAvgArray = betterAvgObj.arr;
            int betterLen = betterAvgArray.length;
            //浮点数的比较不可以使用== 浮点数采用“尾数+阶码”的编码方式，类似于科学计数法的“有效数字+指数”的表示方式。
            //二进制无法精确表示大部分的十进制小数
            //平均值相同那么返回0 因为无法移动
            if (Double.compare(lessAvg, betterAvg) == 0) {
                return 0;
            }
            //将较大平均值的数移动到较小平均值数集合中去
            Set<Integer> lessAvgSet = toSet(lessAvgArray);
            //较大平均的数组进行排序，我们可以进行magic要求数满足 当前这个数大于较小平均值，小于较大平均值
            Arrays.sort(betterAvgArray);
            //可以进行magic 操作的次数
            int optCount = 0;
            for (int temp : betterAvgArray) {
                //当前数 大于较小平均值，这样移动到较小平均值集合才能让较小平均值集合的平均值上升
                //当前数 小于较大平均值，这样移出较大平均值集合才能让较大平均值集合的平均值上升
                if (temp > lessAvg && temp < betterAvg) {
                    //能够成功假如到 较小数集合 说明较小数集合之前不存在temp
                    if (lessAvgSet.add(temp)) {
                        //操作次数++
                        optCount++;
                        //较小平均值之和++
                        lessSum += temp;
                        //更新平均值
                        lessAvg = (lessSum) / (double) (lessLen + 1);
                        //较大值之和--
                        betterSum -= temp;
                        //更新平均值
                        betterAvg = (betterSum) / (double) (betterLen + 1);
                    }
                } else {
                    //说明当前数不满足了（temp > lessAvg && temp < betterAvg） 那么直接跳出
                    break;
                }
            }
            return optCount;
        }

        /***
         * 数组是否为null or 空数组
         * @param arr 需要判断的数组
         * @return 否为null or 空数组
         */
        static boolean isArrayEmpty(int[] arr) {
            return arr == null || arr.length == 0;
        }

        /**
         * 数组转set
         *
         * @param arr
         * @return
         */
        static Set<Integer> toSet(int[] arr) {
            return Arrays.stream(arr)
                    .boxed()
                    .collect(Collectors.toSet());
        }

        /**
         * 统计帮助类 记录平均值，总和，并且持有数组
         */
        static class StaticHelp {
            long sum;
            double avg;
            int[] arr;

            private static StaticHelp of(int[] arr) {
                IntSummaryStatistics intSummaryStatistics = IntStream.of(arr)
                        .summaryStatistics();
                StaticHelp result = new StaticHelp();
                result.sum = intSummaryStatistics.getSum();
                result.avg = intSummaryStatistics.getAverage();
                result.arr = arr;
                return result;
            }

            /*****
             * 对 数组进行统计，并且将较小平均值的数组放在 Pair的key
             */
            public static Pair<StaticHelp, StaticHelp> lessAvgFirst(int[] arr1, int[] arr2) {
                StaticHelp lessAvgObj = of(arr1);
                StaticHelp betterAvgObj = of(arr2);
                if (Double.compare(lessAvgObj.avg, betterAvgObj.avg) > 0) {
                    StaticHelp temp = betterAvgObj;
                    betterAvgObj = lessAvgObj;
                    lessAvgObj = temp;
                }
                return new Pair<>(lessAvgObj, betterAvgObj);
            }
        }
    }

    /***
     * 给定一个函数f，可以1～5的数字等概率返回一个。请加工出1～7的数字等概率返回一个的函数g。
     * 给定一个函数f，可以a~b的数字等概率返回一个。请加工出c～d的数字等概率返回一个的函数g。
     * 给定一个函数f，以p概率返回0，以1-p概率返回1。请加工出等概率返回0和1的函数g
     */
    static class RandomNumGenerate {

        /***
         *给定一个函数f，可以1～5的数字等概率返回一个。请加工出1～7的数字等概率返回一个的函数g。
         * 第一步使用f 创建0 1随机发生器
         * 第二步骤 使用二进制随机模拟每一位，必要的时候使用 do while现在产生的数是目标范围的数
         */
        static int solution1() {
            //1~7
            //2进制 只需要 111 =1+2+4 可以表示1——7
            //随机发生1-7之间的数
            //如果题目要求不包含7 那么使用oneZeroRandomGenerate的do while即可
            return (oneZeroRandomGenerate() << 2)
                    + (oneZeroRandomGenerate() << 1)
                    + (oneZeroRandomGenerate());
        }

        static int solution2() {
            int num1;
            int num2;
            do {
                num1 = p0Rather1();
                num2 = p0Rather1();
                //num1==num2 以为着二者同时为1 or 0，do while保证必定一个0 一个1 概率都是1/2
            } while (num1 == num2);
            //0 1返回0
            if (num1 == 0) {
                return 0;
            } else {
                //1 0 返回1
                return 1;
            }
        }

        /**
         * p概率产生0 1-p产生1
         */
        static int p0Rather1() {
            return Math.random() > 0.3 ? 0 : 1;
        }

        /***
         * 第一步使用f 创建0 1随机发生器
         * @return 0 or 1 等概率
         */
        static int oneZeroRandomGenerate() {
            int res;
            do {
                res = f1();
                if (res == 1 || res == 2) {
                    return 1;
                }
                if (res == 3 || res == 4) {
                    return 0;
                }
            } while (res == 5);
            return res;
        }

        static int f1() {
            return (int) (Math.random() * 5 + 1);
        }

        public static void main(String[] args) {
//            System.out.println(f());
//            System.out.println(oneZeroRandomGenerate());
            System.out.println(solution1());
        }
    }

    public static void main(String[] args) {
        float d1 = 0.9f - 0.8f;
        float d2 = 1.0f - 0.9f;
        System.out.println("==比较:" + (d1 == d2));
        System.out.println("转string比较:" + String.valueOf(d1).equals(String.valueOf(d2)));
        BigDecimal d1Big = BigDecimal.valueOf(d1);
        BigDecimal d2Big = BigDecimal.valueOf(d2);
        System.out.println("BigDecimal equals比较:" + d1Big.equals(d2Big));
        System.out.println("Float.compare比较:" + (Float.compare(d1, d2) == 0));
        System.out.println("BigDecimal.compare比较:" + (d1Big.compareTo(d2Big) == 0));
    }
}
